package org.twdata.pipeline;

import org.springframework.beans.*;
import org.springframework.beans.factory.*;

/**
 *  Uses Spring to create instances of stages for a particular category and sets
 *  categorical parameters. All stages created with this builder will share
 *  common configuration. Per request configuration is, of course, handled by
 *  PipelineContext
 */
public class SpringStageBuilder implements StageBuilder, BeanFactoryAware {

    private MutablePropertyValues pvals = null;
    private String id;
    private StageManager stageManager;
    private BeanFactory factory;


    /**  Constructor */
    public SpringStageBuilder() {
        pvals = new MutablePropertyValues();
    }


    /**
     *  Sets the bean factory
     *
     *@param  factory  The new beanFactory value
     */
    public void setBeanFactory(BeanFactory factory) {
        this.factory = factory;
    }


    /**
     *  Adds a parameter to set on stage instances created by this builder.
     *
     *@param  key  The parameter name
     *@param  val  The parameter value
     */
    public void addParameter(String key, Object val) {
        pvals.addPropertyValue(key, val);
    }


    /**
     *  Sets the id of the stage to create
     *
     *@param  id  The new stage id value
     */
    public void setStageId(String id) throws StageNotFoundException {
        try {
            if (stageManager.getStage(id) == null) {
                throw new StageNotFoundException(id);
            } 
        } catch (PipelineException ex) {
            throw new StageNotFoundException(id, ex);
        }
        this.id = id;
    }


    /**
     *  Sets the stage manager to use to retrieve stage instances.
     *
     *@param  manager  The new stageManager value
     */
    public void setStageManager(StageManager manager) {
        this.stageManager = manager;
    }


    /**
     *  Retrieves a stage, sets its properties, then sets it up with the context
     *
     *@param  ctx                    The pipeline context
     *@return                        The configured stage instance
     *@exception  PipelineException  If something goes wrong
     */
    public Stage build(PipelineContext ctx)
        throws PipelineException {
        Stage stage = stageManager.getStage(id);
        stage.setId(id);
        BeanWrapper wrapper = new BeanWrapperImpl(stage);
        wrapper.setPropertyValues(pvals);
        stage.setup(ctx);
        return (Stage) stage;
    }

}

